package com.kamistoat.ruoyi.ruoyimodulessystem.controller;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import com.kamistoat.ruoyi.ruoyiapisystem.domain.SysMenu;
import com.kamistoat.ruoyi.ruoyiapisystem.entity.SysMenuEntity;
import com.kamistoat.ruoyi.ruoyicommoncore.constant.UserConstants;
import com.kamistoat.ruoyi.ruoyicommoncore.utils.StringUtils;
import com.kamistoat.ruoyi.ruoyicommoncore.web.controller.BaseController;
import com.kamistoat.ruoyi.ruoyicommoncore.web.domain.AjaxResult;
import com.kamistoat.ruoyi.ruoyicommonlog.annotation.Log;
import com.kamistoat.ruoyi.ruoyicommonlog.enums.BusinessType;
import com.kamistoat.ruoyi.ruoyicommonsecurity.annotation.RequiresPermissions;
import com.kamistoat.ruoyi.ruoyicommonsecurity.utils.SecurityUtils;
import com.kamistoat.ruoyi.ruoyimodulessystem.service.SysMenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


/**
 * 菜单权限表
 *
 * @author kamistoat
 * @email linjianshanke@163.com
 * @date 2022-08-09 10:34:46
 */
@RestController
@RequestMapping("/menu")
public class SysMenuController extends BaseController {
    @Autowired
    private SysMenuService sysMenuService;


    /**
     * 获取用户拥有的所有菜单权限列表
     */
    @RequiresPermissions("system:menu:list")
    @GetMapping("/list")
    public AjaxResult list(SysMenu sysMenu) {
        // 从ThreadLocal中获取UserId
        Long userId = SecurityUtils.getUserId();
        List<SysMenuEntity> sysMenuEntityList = sysMenuService.selectMenuList(
                StringUtils.isNull(sysMenu) ? new SysMenu() : sysMenu, userId);
        return AjaxResult.success(entity2Vo(sysMenuEntityList));
    }

    /**
     * 根据菜单权限编号获取详细信息。当然前提是用户本身得拥有这项菜单权限。
     * 该接口正常情况下只会被正在登录的用户调用。
     */
    @RequiresPermissions("system:menu:query")
    @GetMapping(value = "/{menuId}")
    public AjaxResult getInfo(@PathVariable("menuId") Long menuId) {
        SysMenuEntity sysMenuEntity = sysMenuService.selectMenuById(menuId);
        return AjaxResult.success(entity2Vo(sysMenuEntity));
    }

    /**
     * 获取用户拥有的菜单权限下拉树列表
     */
    @GetMapping("/treeselect")
    public AjaxResult treeselect(SysMenu sysMenu) {
        List<SysMenuEntity> sysMenuEntityList = sysMenuService.selectMenuList(
                StringUtils.isNull(sysMenu) ? new SysMenu() : sysMenu, SecurityUtils.getUserId());
        return AjaxResult.success(sysMenuService.buildMenuTreeSelect(entity2Vo(sysMenuEntityList)));
    }

    /**
     * 加载指定roleId的菜单权限列表树
     */
    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
    public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
        if (!SecurityUtils.curLoginUserIsAdmin() && !SecurityUtils.getLoginUser().getRoleIds().contains(roleId)) {
            return AjaxResult.error("你无权访问roleId为" + roleId + "的角色!");
        }

        AjaxResult ajax = AjaxResult.success();
        // 获取指定角色的权限类列表
        List<SysMenuEntity> sysMenuEntityList = sysMenuService.selectMenuList(
                new SysMenu(), SecurityUtils.getUserId());
        // checkedKeys 保存指定角色的权限id列表
        ajax.put("checkedKeys", sysMenuEntityList.stream().map(SysMenuEntity::getMenuId).collect(Collectors.toList()));
        // menus 保存指定角色的权限树
        ajax.put("menus", sysMenuService.buildMenuTreeSelect(entity2Vo(sysMenuEntityList)));
        return ajax;
    }

    /**
     * 新增权限。只有超级管理员可以添加新权限。
     */
    @RequiresPermissions("system:menu:add")
    @Log(title = "菜单权限管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysMenu menu) {
        if (!SecurityUtils.curLoginUserIsAdmin()) {
            return AjaxResult.error("无权限向id为'" + menu.getParentId() + "'的菜单权限下添加子菜单权限.只有超级管理员有权限添加新权限");
        }
        if (sysMenuService.checkMenuNameUnique(menu)) {
            return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败，菜单名称已存在");
        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
            return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败，地址必须以http(s)://开头");
        }
        menu.setCreateBy(SecurityUtils.getUserName());
        menu.setCreateTime(new Date());
        return toAjax(sysMenuService.saveAndRefreshCache(vo2Entity(menu)));
    }

    /**
     * 修改权限
     */
    @RequiresPermissions("system:menu:edit")
    @Log(title = "菜单权限管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysMenu menu) {
        // 权限校验
        SysMenu selfMenu = new SysMenu();
        selfMenu.setMenuId(menu.getMenuId());
        List<SysMenuEntity> allowed = sysMenuService.selectMenuList(selfMenu, SecurityUtils.getUserId());
        if (StringUtils.isNull(allowed) || allowed.size() == 0) {
            return AjaxResult.error("修改菜单权限失败，用户无权限操作该菜单权限");
        }
        if (sysMenuService.checkMenuNameUnique(menu)) {
            return AjaxResult.error("修改菜单权限'" + menu.getMenuName() + "'失败，菜单名称已存在");
        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
            return AjaxResult.error("修改菜单权限'" + menu.getMenuName() + "'失败，地址必须以http(s)://开头");
        } else if (menu.getMenuId().equals(menu.getParentId())) {
            return AjaxResult.error("修改菜单权限'" + menu.getMenuName() + "'失败，上级菜单不能选择自己");
        }
        menu.setUpdateBy(SecurityUtils.getUserName());
        return toAjax(sysMenuService.updateById(vo2Entity(menu)));
    }

    /**
     * 删除菜单权限
     */
    @RequiresPermissions("system:menu:remove")
    @Log(title = "菜单管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{menuId}")
    public AjaxResult remove(@PathVariable("menuId") Long menuId) {
        // 仅用作权限验证
        SysMenu selfMenu = new SysMenu();
        selfMenu.setMenuId(menuId);
        List<SysMenuEntity> allowed = sysMenuService.selectMenuList(selfMenu, SecurityUtils.getUserId());
        if (StringUtils.isNull(allowed) || allowed.size() == 0) {
            return AjaxResult.error("修改菜单权限失败，用户无权限操作该菜单权限");
        }

        if (sysMenuService.hasChildByMenuId(menuId)) {
            return AjaxResult.error("存在子菜单权限,不允许删除");
        }

        if (sysMenuService.checkMenuExistRole(menuId)) {
            return AjaxResult.error("菜单权限已分配给角色,不允许删除");
        }
        return toAjax(sysMenuService.removeById(menuId));
    }

    /**
     * 获取用户拥有的导航菜单权限，构造成路由结构
     *
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters() {
        List<SysMenuEntity> sysMenuEntityList = sysMenuService.selectMenuList(new SysMenu(), SecurityUtils.getUserId());
        List<SysMenu> routeSysMenuList = sysMenuService.getChildPerms(entity2Vo(sysMenuEntityList), 0L);
        return AjaxResult.success(sysMenuService.buildMenuRouters(routeSysMenuList));
    }


    /**
     * Entity 和 Vo类的转换
     */
    private List<SysMenu> entity2Vo(List<SysMenuEntity> sysMenuEntityList) {
        return
                sysMenuEntityList.stream().map(sysMenuEntity -> {
                    SysMenu sysMenu = new SysMenu();
                    BeanUtils.copyProperties(sysMenuEntity, sysMenu);
                    return sysMenu;
                }).collect(Collectors.toList());
    }

    private SysMenu entity2Vo(SysMenuEntity sysMenuEntity) {
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyProperties(sysMenuEntity, sysMenu);
        return sysMenu;
    }

    private List<SysMenuEntity> vo2Entity(List<SysMenu> sysMenuList) {
        return
                sysMenuList.stream().map(sysMenu -> {
                    SysMenuEntity sysMenuEntity = new SysMenuEntity();
                    BeanUtils.copyProperties(sysMenu, sysMenuEntity);
                    return sysMenuEntity;
                }).collect(Collectors.toList());
    }

    private SysMenuEntity vo2Entity(SysMenu sysMenu) {
        SysMenuEntity sysMenuEntity = new SysMenuEntity();
        BeanUtils.copyProperties(sysMenu, sysMenuEntity);
        return sysMenuEntity;
    }

}
